/******************************************************************************
 * Filename : uc_poll.h
 * Created  : 2009-8-8 by franco.yin
 * Description -
 *
 ******************************************************************************/

#ifndef _UC_POLL_H
#define _UC_POLL_H

#ifdef __cplusplus
extern "C" {
#endif

#include "uc_public.h"
#include "uc_hash.h"
#include "uc_list.h"
#include "uc_time.h"
#include "uc_thread.h"
#include "uc_socket.h"
#include "uc_thread.h"

//#define UCPOLL_USE_SELECT 1

#define UCPOLL_MAX_EVENT_NUM 		2048
#define UCPOLL_HASH_SIZE 			1024
#define UCPOLL_MAGIC 				0x5949527a
#define UCPOLL_TIMER_IN_DEFAULT	1000
#define UCPOLL_PKT_MAX_LEN		(1024 * 1024 * 10)

enum ucpoll_type {
	UCPOLL_EVENT_SERVER,
	UCPOLL_EVENT_TIMER,
};

enum ucpoll_event_type {
	UCPOLL_IN = 1,
	UCPOLL_OUT,
	UCPOLL_ERR
};

enum ucpoll_func_action {
	UCPOLL_FUNC_IDLE,
	UCPOLL_FUNC_DEL
};

typedef int (*ucpoll_do_srv) (int fd, int type, void *pPoll, void *pEvt, void *param);
typedef int (*ucpoll_do_wakeup) (void *pPoll, void *param);
typedef int (*ucpoll_do_connect) (void *pPoll, int fd, void *param);
typedef int (*ucpoll_do_tmr) (void *pPoll, void *param);
//typedef int (*ucpoll_do_tmr) (void *pPoll, UC_S64 base_diff, void *param);


typedef struct _ucmsg_node {
	ucnode_s node;
	ucmsg_s msg;
}ucmsg_node_s;

typedef struct _ucpoll_poll {
	int magic;
	uchash_table_s *pHashSrv;
	uclist_s list_timer_in;
	uclist_s list_release;

#ifdef UCPOLL_USE_SELECT
	fd_set irfds, iwfds, iefds, orfds, owfds, oefds;
	int max_fd;
#else
	struct epoll_event epoll_ev[UCPOLL_MAX_EVENT_NUM];
	int fd_epoll;
#endif

	int last_act_srv;
	int last_act_tmr;
	int last_act_fd;

	ucpoll_do_tmr pFunTimer_in;

	ucpoll_do_tmr pFunTimer_out;
	int timer_out_timeout;
	int timer_out_valid_times;
	void *timer_out_param;
	int timer_out_notify_times;
	UC_S64 timer_out_last_notify;

	ucpoll_do_wakeup pFunWakeup;
	int pipe_wakeup[2];
	void *pEvtWakeup;
	void *pParamWakeup;

	int max_event;
	UC_S64 last_time;
	int run;
} ucpoll_poll_s;

typedef struct _ucpoll_event_fd {
	ucpoll_do_srv pFun_srv;
	void *pParam;
#ifndef UCPOLL_USE_SELECT
	struct epoll_event ep_event;
#endif
	int fd_event;
} ucpoll_event_fd_s;

typedef struct _ucpoll_event_timer {
	ucpoll_do_connect pFun_tmr;
	int fd;
	void *pEvt;
	void *pParam;
	ucpoll_poll_s *pPoll;
	int timeout;
	UC_S64 last_notify;
} ucpoll_event_timer_s;

typedef struct _ucpoll_event {
	ucnode_s node_list;
	uchash_node_s node_hash;
	ucpoll_poll_s *pPoll;
	int if_used;

	union {
		ucpoll_event_fd_s event_fd;
		ucpoll_event_timer_s event_timer;
	};
} ucpoll_event_s;

typedef struct _ucpoll_fd_plus_data {
	ucnode_s node;

	int data_len;
	int sent_len;

	void *pFree;
	char *pData;

	char data[0];
} ucpoll_fd_plus_data_s;

typedef struct _ucpoll_fd_plus {
	int fd;
	int pkt_max_len;

	uclist_s list_data;
	int list_data_cnt;

	ucpoll_fd_plus_data_s *pSend;
	int recved_len;

	ucmsg_s msg;
	int if_recvd_head;
	ucmsg_node_s *pMsg;
} ucpoll_fd_plus_s;

#define ucpoll_new() _ucpoll_new_ext(UCPOLL_MAX_EVENT_NUM, __FILE__, __LINE__)
#define ucpoll_new_ext(maxEventCount) _ucpoll_new_ext(maxEventCount, __FILE__, __LINE__)
extern void *_ucpoll_new_ext(int maxEventCount, const char *file, int line);

#define ucpoll_free(pPollNod) _ucpoll_free(pPollNod, __FILE__, __LINE__)
extern void _ucpoll_free(void *pPollNode, const char *file, int line);

#define ucpoll_add_server(pPollNode, fd, pFunSrv, pParam) _ucpoll_add_server(pPollNode, fd, pFunSrv, pParam, __FILE__, __LINE__)
extern void *_ucpoll_add_server(void *pPollNode, int fd, ucpoll_do_srv pFunSrv, void *pParam, const char *file, int line);
#define ucpoll_del_server(pSrvNode) _ucpoll_del_server(pSrvNode, __func__, __LINE__)
extern int ucpoll_add_wakeup(void *pPollNode, ucpoll_do_wakeup pFunWakeup, void *pParam);
extern int ucpoll_wakeup(void *pPollNode);
extern int _ucpoll_del_server(void *pSrvNode, const char *func, int line);
extern void *ucpoll_get_server_by_fd(void *pPoll, const int fd);
extern int ucpoll_del_server_by_fd(void *pPollNode, int fd);

extern int ucpoll_add_connect(void *pPollNode, char *ip, int port, int type, char *dev, int timeout, ucpoll_do_connect pFunTmr, void *pParam);

extern int ucpoll_add_timer(void *pPollNode, int timeout, int valid_times, ucpoll_do_tmr pFunTmr, void *pParam);
extern int ucpoll_del_timer(void *pPollNode);

#define ucpoll_set(pSrvNode, rd, wr, err) _ucpoll_set(pSrvNode, rd, wr, err, __FILE__, __LINE__)
#define ucpoll_set_et(pSrvNode, rd, wr, err) _ucpoll_set_et(pSrvNode, rd, wr, err, __FILE__, __LINE__)

#define ucpoll_unset(pSrvNode, rd, wr, err) _ucpoll_unset(pSrvNode, rd, wr, err, __FILE__, __LINE__)
extern int _ucpoll_set(void *pSrvNode, int rd, int wr, int err, const char *file, int line);
extern int _ucpoll_set_et(void *pSrvNode, int rd, int wr, int err, char *file, int line);

extern int _ucpoll_unset(void *pSrvNode, int rd, int wr, int err, char *file, int line);

#define ucpoll_wait(pPollNode) _ucpoll_wait(pPollNode, 0, __FILE__, __LINE__)
#define ucpoll_wait_once_nonblock(pPollNode, nonblock_timeout) _ucpoll_wait(pPollNode, nonblock_timeout, __FILE__, __LINE__)
extern int _ucpoll_wait(void *pPollNode, int nonblock_timeout, const char *file, int line);

extern int ucpoll_stop(void *pPollNode);

extern void *ucpoll_fd_plus_creat(int tcp_fd, int pkt_max_len);
extern void ucpoll_fd_plus_free(void *pFdPlus);
extern void ucpoll_fd_plus_cache_clean(void *pFdPlus);
extern int ucpoll_fd_plus_cache_cnt(void *pFdPlus);
extern int ucpoll_fd_plus_send(void *pFdPlus, char *pData, int len, void *pDataFree);
extern int ucpoll_fd_plus_poll_out(void *pFdPlus);
extern int ucpoll_fd_plus_recv_head(void *pFdPlus, ucmsg_s *pMsg, int *if_recv_ok, int *if_block);
extern int ucpoll_fd_plus_recv_data(void *pFdPlus, char *pData, int data_len, int *if_recv_ok, int *if_block);
extern int ucpoll_fd_plus_recv_msg(void *pFdPlus, ucmsg_node_s **ppMsg);

#ifdef __cplusplus
}
#endif

#endif				/* _UC_POLL_H */
